---
layout: howTo
---
<!--
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements. See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership. The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied. See the License for the
    specific language governing permissions and limitations
    under the License.
-->

<!-- Main -->
<div id="main">

  <!-- Introduction -->
    <section id="intro" class="main special">
      <div class="">
        <div class="content align-left">
          <header class="major">
            <h1>How to customize mail processing</h1>
          </header>
            <header class="major">
                <h2><b>Mail processing component overview</b></h2>
            </header>
          <p class="align-left">At the heart of James lies the Mailet container, which allows mail processing. This is
          splitted into smaller units, with specific responsibilities:

          </p>

          <ul class="no-padding">
            <li><b>Mailets:</b> Are operations performed with the mail: modifying it, performing a side-effect, etc...</li>
            <li><b>Matchers:</b> Are per-recipient conditions for mailet executions</li>
            <li><b>Processors:</b> Are matcher/mailet pair execution threads</li>
          </ul>

          <p> Read <a href="/server/feature-mailetcontainer.html">this</a> for more explanations of mailet container concepts.</p>

          <p>Once we define the mailet container content through the <a href="/server/config-mailetcontainer.html">mailetcontailer.xml</a> file.
          Hence, we can arrange James standard components listed <a href="/server/3/dev-provided-mailets.html">here</a> to achieve basic logic. But what if our goals are more
          complex? What if we need our own processing components?</p>

          <p>This page will propose a 'hands on practice' how-to using James 3.7.3. We will implement a custom mailet and a custom matcher,
          then deploy it in a James server.</p>

          <p>We need to choose our use case. We will, when a mail is delayed over one day, write a mail to the original sender
          to inform him about the delay, say that we are sorry, and send him a promotion code...<pre></pre></p>


          <header class="major">
            <h2><b>Writing custom mailets and matchers</b></h2>
          </header>

          <p>None of the matchers and mailets available in James allows us to implement what we want. We will have to
          write our own mailet and matcher in a separated maven project depending on James Mailet API.</p>

          <p>We will write a <a href="https://github.com/apache/james-project/blob/master/examples/custom-mailets/src/main/java/org/apache/james/examples/custom/mailets/IsDelayedForMoreThan.java">IsDelayedForMoreThan</a> matcher with a configurable delay. If the Sent Date of incoming emails is older than specified delay, then the emails
          should be matched (return all mail recipients). Otherwise, we just return an empty list of recipients.</p>

          <p>To ease our Job, we can rely on the <b>org.apache.james.apache-mailet-base</b> maven project, which provides us a <b>GenericMatcher</b> that we can extend.</p>

          <p>Here is the dependency:</p>

          <pre><code>&lt;dependency&gt;
    &lt;groupId&gt;org.apache.james&lt;/groupId&gt;
    &lt;artifactId&gt;apache-mailet-base&lt;/artifactId&gt;
&lt;/dependency&gt;</code></pre>

          <p>The main method of a matcher is the <b>match</b> method:</p>

          <pre><code>Collection&lt;MailAddress&gt; match(Mail mail) throws MessagingException;</code></pre>

          <p>For us, it becomes, with <b>maxDelay</b> being previously configured:</p>

          <pre><code>private final Clock clock;
private Duration maxDelay;

@Override
public Collection&lt;MailAddress&gt; match(Mail mail) throws MessagingException {
    Date sentDate = mail.getMessage().getSentDate();

    if (clock.instant().isAfter(sentDate.toInstant().plusMillis(maxDelay.toMillis()))) {
        return ImmutableList.copyOf(mail.getRecipients());
    }
    return ImmutableList.of();
}</code></pre>

            <p><b>GenericMatcher</b> exposes us the condition that had been configured. We will use it to compute <b>maxDelay</b>.
          We can do it in the <b>init()</b> method exposed by the generic matcher:</p>

          <pre><code>
public static final TimeConverter.Unit DEFAULT_UNIT = TimeConverter.Unit.HOURS;

@Override
public void init() {
    String condition = getCondition();
    maxDelay = Duration.ofMillis(TimeConverter.getMilliSeconds(condition, DEFAULT_UNIT));
}</code></pre>

          <p>Now, let's take a look at the <a href="https://github.com/apache/james-project/blob/master/examples/custom-mailets/src/main/java/org/apache/james/examples/custom/mailets/SendPromotionCode.java">SendPromotionCode</a> mailet. Of course, we want to write a generic mailet
             with a configurable reason (why are we sending the promotion code). To keep things simple, only one promotion
             code will be used, and will be written in the configuration. We can here also simply extend the
              <b>GenericMailet</b> helper class.</p>

          <p>The main method of a mailet is the <b>service</b> method:</p>

          <pre><code>void service(Mail mail) throws MessagingException</code></pre>

          <p>For us, it becomes, with <b>reason</b> and <b>promotionCode</b> being previously configured:</p>

            <pre><code>public static final boolean REPLY_TO_SENDER_ONLY = false;

private String reason;
private String promotionCode;

@Override
public void service(Mail mail) throws MessagingException {
    MimeMessage response = (MimeMessage) mail.getMessage()
        .reply(REPLY_TO_SENDER_ONLY);

    response.setText(reason + "\n\n" +
        "Here is the following promotion code that you can use on your next order: " + promotionCode);

    MailAddress sender = getMailetContext().getPostmaster();
    ImmutableList&lt;MailAddress&gt; recipients = ImmutableList.of(mail.getSender());

    getMailetContext()
        .sendMail(sender, recipients, response);
}</code></pre>

          <p>Note that we can interact with the mail server through the mailet context for sending mails, knowing postmaster, etc...</p>

            <p><b>GenericMailet</b> exposes us the 'init parameters' that had been configured for this mailet. We will
                use it to retrieve <b>reason</b> and <b>promotionCode</b>.
                We can do it in the <b>init()</b> method exposed by the generic mailet:</p>

            <pre><code>    @Override
public void init() throws MessagingException {
    reason = getInitParameter("reason");
    promotionCode = getInitParameter("promotionCode");

    if (Strings.isNullOrEmpty(reason)) {
        throw new MessagingException("'reason' is compulsory");
    }
    if (Strings.isNullOrEmpty(promotionCode)) {
        throw new MessagingException("'promotionCode' is compulsory");
    }
}</code></pre>

        <p>You can retrieve the sources of this mini-project on <a href="https://github.com/apache/james-project/tree/master/examples/custom-mailets">GitHub</a></p>

        <header class="major">
           <h2><b>Loading custom mailets with James</b></h2>
        </header>

        <p>Now is the time we will run James with our awesome matcher and mailet configured.</p>

        <p>First, we will need to compile our project with <code>mvn clean install</code>. A jar will be outputted in the target directory.</p>

        <p>Then, we will write the <code>mailetcontainer.xml</code> file expressing the logic we want:</p>

        <pre><code>
&lt;mailetcontainer enableJmx="true">

&lt;context&gt;
    &lt;postmaster&gt;postmaster@localhost&lt;/postmaster&gt;
&lt;/context&gt;

&lt;spooler&gt;
    &lt;threads&gt;20&lt;/threads&gt;
&lt;/spooler&gt;

&lt;processors&gt;
    &lt;processor state="root" enableJmx="true"&gt;
        &lt;mailet match="All" class="PostmasterAlias"/&gt;
        &lt;mailet match="org.apache.james.examples.custom.mailets.IsDelayedForMoreThan=1 day"
                class="org.apache.james.examples.custom.mailets.SendPromotionCode"&gt;
            &lt;reason&gt;Your email had been delayed for a long time. Because we are sorry about it, please find the
            following promotion code.&lt;/reason&gt;
            &lt;promotionCode&gt;1542-2563-5469&lt;/promotionCode&gt;
        &lt;/mailet&gt;
        &lt;!-- Rest of the configuration --&gt;
    &lt;/processor&gt;

    &lt;!-- Other processors --&gt;
&lt;/processors&gt;
&lt;/mailetcontainer&gt;</code></pre>

        <p>Finally, we will start a James server using that. We will rely on docker default image for simplicity.
            We need to be using the <b>mailetcontainer.xml</b> configuration that we had been writing and position
            the jar in the <b>extensions-jars</b> folder (specific to guice). This can be achieved with the following command:</p>

        <pre><code>docker run -p "25:25" -p "143:143" \
               -v "$PWD/src/main/resources/mailetcontainer.xml:/root/conf/mailetcontainer.xml" \
               -v "$PWD/target/custom-mailets.jar:/root/extensions-jars/custom-mailets.jar" \
        apache/james:memory-latest --generate-keystore</code></pre>

        </div>
          <footer class="major">
              <ul class="actions align-center">
                  <li><a href="index.html" class="button">go back to other how-tos</a></li>
              </ul>
          </footer>
      </div>
    </section>

</div>
